The moving average function
The moving average averages each observation of a series with its
surrounding observations in chronological order. The main components of
the MA function are:
The rolling window structure
The most common types of window structures are:
The one-sided window: a sliding window with a width of n
which groups each observation of the series with its past consecutive
n-1 observations.
The two-sided window: rolling window which groups each
observation with its past \(n_1\) and
future \(n_2\) observations.
The MA attributes
The MA function has two primary attributes that are derived directly
from the window structure.
Order: this defines the magnitude of the MA and is equal to the
length of the window
Cost: the cost is the loss of observations during the
transformation of the origin series to the smoothed series by the MA
process.
The main applications of the MA function are:
Noise reduction: the use of the MA method creates a smoothing
effect that reduces series variation, smoothing the random noise and
outliers.
De-seasonalize: used to remove the seasonal component
Forecasting: can be used to forecast
Let’s see an example of a one-sided MA with an arithmetic average,
known as a simple MA, a two-sided MA and a weighted MA.
The simple moving average
Let’s build our own simple moving average function. We will do so by
creating a rolling window function and an average function.
head(lags(USVSales, l = 3))
y y_1 y_2 y_3
[1,] 1092.1 969.9 1061.8 1084.4
[2,] 1451.1 1092.1 969.9 1061.8
[3,] 1354.4 1451.1 1092.1 969.9
[4,] 1377.1 1354.4 1451.1 1092.1
[5,] 1459.8 1377.1 1354.4 1451.1
[6,] 1202.0 1459.8 1377.1 1354.4
Two-sided MA
two_sided_ma <- ts_ma(ts.obj = USVSales,
n = c(2, 5),
n_left = 6,
n_right = 5,
plot = TRUE,
multiple = TRUE,
margin = 0.4)
A line object has been specified, but lines is not in the mode
Adding lines to the mode...
A line object has been specified, but lines is not in the mode
Adding lines to the mode...
A line object has been specified, but lines is not in the mode
Adding lines to the mode...
The higher the order of the function, the smoother the output.
A simple MA versus a two-sided MA
A two-sided MA is more approprate to apply as a smoother or data
filter method. A one-sided MA makes sense when you need to have the most
recent observations.
The time series components
Patterns in time series analysis can be categorized into one of the
following:
Structural Patterns: also known as series components. There are
three types - trend, cycle, and seasonal.
Non-structural: also known as the irregular component and refers
to any other types of patterns in the data.
We can use these two groups of patterns to express time series data
using the following equation when the series has an additive
structure:
\[
Y_t = T_t + S_t + C_t + I_t
\]
And when the series has a multiplicative structure:
\[
Y_t = T_t \times S_t \times C_t \times I_t
\]
The cycle component
ts_info(USUnRate)
The USUnRate series is a ts object with 1 variable and 864 observations
Frequency: 12
Start time: 1948 1
End time: 2019 12
We don’t need to plot the entire series, so we will subset it with a
window function:
The trend component
A trend is a general direction in a series.
The seasonal component
A seasonal trend is one that has repeated variation over time.
The seasonal component versus the cycle component

The plot above shows a seasonal cycle.

This plot shows cycles.
White noise
A white noise pattern is a lack of a pattern. There are some methods
to test if a series is white noise.
The irregular component
This is the remainder between the series and structural
components.
The additive versus the multiplicative model
We classify a series as additive whenever there is growth in the
trend, or if the amplitude of the seasonal component remains the same
over time.
We classify a series as multiplicative whenever the growth of the
trend or the magnitude of the seasonal component increases or decreases
by some multiplicity from period to period over time.
Here is an example of an additive series:
Here is an example of a multiplicative series:
Handling multiplicative series
Most forecasting models assume that the variation of the input series
remains constant over time. This usually holds for a series with an
additive structure, but fails with a multiplicative structure. The
common solution is to apply a data transformation:
air_passenger_lambda
[1] -0.2947156
We can use the coefficient to transform the input series with the
BoxCox transformation and plot it:
The decomposition of time series
Once the data has been cleaned and reformatted, we need to identify
the structure of the series components. The decomposition of a series is
a generic name for the process of separating a series into its
components.
Classical seasonal decomposition
This is a three step process:
- trend estimation: uses the MA function to remove the seasonal
component from the series. THe order of the MA function is determined by
the frequency of the series.
- Seasonal component estimation: Two step process that starts with
detrending the series by subtracting the trend estimation from the
previous step. After the series is detrended, the next step is to
estimate the seasonal component for each frequency unit. This is done by
grouping the observations by their frequency unit and then averaging
each group.
- Irregular component estimation: subtracting the estimation of the
trend and seasonal components from the original series.
We can do all of this with the decompose() function:
str(usv_decomposed)
List of 6
$ x : Time-Series [1:528] from 1976 to 2020: 885 995 1244 1191 1203 ...
$ seasonal: Time-Series [1:528] from 1976 to 2020: -225.2 -102.4 143 34.5 147.9 ...
$ trend : Time-Series [1:528] from 1976 to 2020: NA NA NA NA NA ...
$ random : Time-Series [1:528] from 1976 to 2020: NA NA NA NA NA ...
$ figure : num [1:12] -225.2 -102.4 143 34.5 147.9 ...
$ type : chr "additive"
- attr(*, "class")= chr "decomposed.ts"
x is the original series
seasonal is the estimate of the seasonal
trend
trend is the estimate of the series trend
random is the irregular component
figure estimated seasonal figure only
type the type of decomposition, either additive or
multiplicative

And with a multiplicative model:

One limitation of the classical decomposition method is that the
seasonal component uses the arithmetic average. This means that there is
a single seasonal component estimation for each cycle unit. This is fine
with additive models, but can be problematic with multiplicative models
since the seasonal aspect changes over time.
Seasonal Adjustment
Seasonal adjustment is the process of removing the seasonal
fluctuation from a series. The transformation process of the seasonal
adjustment method is straightforward:
- Estimate the seasonal component using a decomposition process
- Remove the seasonal component from the series, which leaves the
series with only the trend and the irregular component
- Optionall, you can apply a smoothing function to remove noise and
outliers
LS0tCnRpdGxlOiAiQ2hhcHRlciA0OiBEZWNvbXBvc2l0aW9uIG9mIFRpbWUgU2VyaWVzIERhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgVGhlIG1vdmluZyBhdmVyYWdlIGZ1bmN0aW9uCgpUaGUgbW92aW5nIGF2ZXJhZ2UgYXZlcmFnZXMgZWFjaCBvYnNlcnZhdGlvbiBvZiBhIHNlcmllcyB3aXRoIGl0cyBzdXJyb3VuZGluZyBvYnNlcnZhdGlvbnMgaW4gY2hyb25vbG9naWNhbCBvcmRlci4gVGhlIG1haW4gY29tcG9uZW50cyBvZiB0aGUgTUEgZnVuY3Rpb24gYXJlOgoKLSAgIFRoZSByb2xsaW5nIHdpbmRvdzogQSBnZW5lcmljIGZ1bmN0aW9uIHRoYXQgc2xpZGVzIGFsb25nIGRhdGEgaW4gY2hyb25vbG9naWNhbCBvcmRlcgoKLSAgIEF2ZXJhZ2UgZnVuY3Rpb246IHRoaXMgaXMgZWl0aGVyIGEgc2ltcGxlIG9yIHdlaWdodGVkIGF2ZXJhZ2UKCiMjIFRoZSByb2xsaW5nIHdpbmRvdyBzdHJ1Y3R1cmUKClRoZSBtb3N0IGNvbW1vbiB0eXBlcyBvZiB3aW5kb3cgc3RydWN0dXJlcyBhcmU6CgotICAgVGhlIG9uZS1zaWRlZCB3aW5kb3c6IGEgc2xpZGluZyB3aW5kb3cgd2l0aCBhIHdpZHRoIG9mICpuKiB3aGljaCBncm91cHMgZWFjaCBvYnNlcnZhdGlvbiBvZiB0aGUgc2VyaWVzIHdpdGggaXRzIHBhc3QgY29uc2VjdXRpdmUgKm4tMSogb2JzZXJ2YXRpb25zLgoKLSAgIFRoZSB0d28tc2lkZWQgd2luZG93OiByb2xsaW5nIHdpbmRvdyB3aGljaCBncm91cHMgZWFjaCBvYnNlcnZhdGlvbiB3aXRoIGl0cyBwYXN0ICRuXzEkIGFuZCBmdXR1cmUgJG5fMiQgb2JzZXJ2YXRpb25zLgoKIyMgVGhlIGF2ZXJhZ2UgbWV0aG9kCgotICAgdGhlIGFyaXRobWV0aWMgYXZlcmFnZTogYmFzZWQgb24gc3VtbWluZyBhbGwgb2JzZXJ2YXRpb25zIGFuZCBkaXZpZGluZyB0aGVtIGJ5IHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCgotICAgVGhlIHdlaWdodGVkIGF2ZXJhZ2U6IGJhc2VkIG9uIGFwcGx5aW5nIGEgd2VpZ2h0IHRvIGVhY2ggb2JzZXJ2YXRpb24gb2YgdGhlIHNlcmllcwoKIyMgVGhlIE1BIGF0dHJpYnV0ZXMKClRoZSBNQSBmdW5jdGlvbiBoYXMgdHdvIHByaW1hcnkgYXR0cmlidXRlcyB0aGF0IGFyZSBkZXJpdmVkIGRpcmVjdGx5IGZyb20gdGhlIHdpbmRvdyBzdHJ1Y3R1cmUuCgotICAgT3JkZXI6IHRoaXMgZGVmaW5lcyB0aGUgbWFnbml0dWRlIG9mIHRoZSBNQSBhbmQgaXMgZXF1YWwgdG8gdGhlIGxlbmd0aCBvZiB0aGUgd2luZG93CgotICAgQ29zdDogdGhlIGNvc3QgaXMgdGhlIGxvc3Mgb2Ygb2JzZXJ2YXRpb25zIGR1cmluZyB0aGUgdHJhbnNmb3JtYXRpb24gb2YgdGhlIG9yaWdpbiBzZXJpZXMgdG8gdGhlIHNtb290aGVkIHNlcmllcyBieSB0aGUgTUEgcHJvY2Vzcy4KClRoZSBtYWluIGFwcGxpY2F0aW9ucyBvZiB0aGUgTUEgZnVuY3Rpb24gYXJlOgoKLSAgIE5vaXNlIHJlZHVjdGlvbjogdGhlIHVzZSBvZiB0aGUgTUEgbWV0aG9kIGNyZWF0ZXMgYSBzbW9vdGhpbmcgZWZmZWN0IHRoYXQgcmVkdWNlcyBzZXJpZXMgdmFyaWF0aW9uLCBzbW9vdGhpbmcgdGhlIHJhbmRvbSBub2lzZSBhbmQgb3V0bGllcnMuCgotICAgRGUtc2Vhc29uYWxpemU6IHVzZWQgdG8gcmVtb3ZlIHRoZSBzZWFzb25hbCBjb21wb25lbnQKCi0gICBGb3JlY2FzdGluZzogY2FuIGJlIHVzZWQgdG8gZm9yZWNhc3QKCkxldCdzIHNlZSBhbiBleGFtcGxlIG9mIGEgb25lLXNpZGVkIE1BIHdpdGggYW4gYXJpdGhtZXRpYyBhdmVyYWdlLCBrbm93biBhcyBhIHNpbXBsZSBNQSwgYSB0d28tc2lkZWQgTUEgYW5kIGEgd2VpZ2h0ZWQgTUEuCgpgYGB7cn0KbGlicmFyeShUU3N0dWRpbykKZGF0YSgiVVNWU2FsZXMiKQoKdHNfaW5mbyhVU1ZTYWxlcykKCnRzX3Bsb3QoVVNWU2FsZXMsCiAgICAgICAgdGl0bGUgPSAiVVMgTW9udGhseSBUb3RhbCBWZWhpY2xlIFNhbGVzIiwKICAgICAgICBZZ3JpZCA9IFRSVUUsCiAgICAgICAgWGdyaWQgPSBUUlVFKQpgYGAKCiMjIFRoZSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UKCkxldCdzIGJ1aWxkIG91ciBvd24gc2ltcGxlIG1vdmluZyBhdmVyYWdlIGZ1bmN0aW9uLiBXZSB3aWxsIGRvIHNvIGJ5IGNyZWF0aW5nIGEgcm9sbGluZyB3aW5kb3cgZnVuY3Rpb24gYW5kIGFuIGF2ZXJhZ2UgZnVuY3Rpb24uCgpgYGB7cn0KbGFncyA8LSBmdW5jdGlvbih0cy5vYmosIGwpIHsKICB0c19tZXJnZWQgPC0gTlVMTAogIAogICMgY3JlYXRpbmcgbiBsYWdzCiAgZm9yIChpIGluIDE6bCkgewogICAgdHNfbWVyZ2VkIDwtIHRzLnVuaW9uKHRzX21lcmdlZCwgc3RhdHM6OmxhZyh0cy5vYmosIGsgPSAtaSkpCiAgfQogIAogICMgbWVyZ2UgdGhlIGxhZ3Mgd2l0aCB0aGUgb3JpZ2luYWwgc2VyaWVzCiAgdHNfbWVyZ2VkIDwtIHRzLnVuaW9uKHRzLm9iaiwgdHNfbWVyZ2VkKQogIAogICMgc2V0IHRoZSBjb2x1bW4gbmFtZXMKICBjb2xuYW1lcyh0c19tZXJnZWQpIDwtIGMoInkiLCBwYXN0ZTAoInlfIiwgMTppKSkKICAKICAjIHJlbW92aW5nIG1pc3NpbmcgdmFsdWVzIGFzIHJlc3VsdHMgb2YgY3JlYXRpbmcgdGhlIGxhZ3MKICB0c19tZXJnZWQgPC0gd2luZG93KHRzX21lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0KHRzLm9iaikgKyAxLAogICAgICAgICAgICAgICAgICAgICAgZW5kID0gZW5kKHRzLm9iaikpCiAgCiAgcmV0dXJuKHRzX21lcmdlZCkKfQoKaGVhZChsYWdzKFVTVlNhbGVzLCBsID0gMykpCmBgYAoKIyMgVHdvLXNpZGVkIE1BCgpgYGB7cn0KdHdvX3NpZGVkX21hIDwtIHRzX21hKHRzLm9iaiA9IFVTVlNhbGVzLAogICAgICAgICAgICAgICAgICAgICAgbiA9IGMoMiwgNSksCiAgICAgICAgICAgICAgICAgICAgICBuX2xlZnQgPSA2LAogICAgICAgICAgICAgICAgICAgICAgbl9yaWdodCA9IDUsCiAgICAgICAgICAgICAgICAgICAgICBwbG90ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IDAuNCkKYGBgCgpUaGUgaGlnaGVyIHRoZSBvcmRlciBvZiB0aGUgZnVuY3Rpb24sIHRoZSBzbW9vdGhlciB0aGUgb3V0cHV0LgoKIyMgQSBzaW1wbGUgTUEgdmVyc3VzIGEgdHdvLXNpZGVkIE1BCgpgYGB7cn0Kb25lX3NpZGVkXzEyIDwtIHRzX21hKFVTVlNhbGVzLCBuID0gTlVMTCwgbl9sZWZ0ID0gMTEsIHBsb3QgPSBGQUxTRSkKdHdvX3NpZGVkXzEyIDwtIHRzX21hKFVTVlNhbGVzLCBuID0gTlVMTCwgbl9sZWZ0ID0gNiwgbl9yaWdodCA9IDUsIHBsb3QgPSBGQUxTRSkKb25lX3NpZGVkIDwtIG9uZV9zaWRlZF8xMiR1bmJhbGFuY2VkX21hXzEyCnR3b19zaWRlZCA8LSB0d29fc2lkZWRfMTIkdW5iYWxhbmNlZF9tYV8xMgoKbWEgPC0gY2JpbmQoVVNWU2FsZXMsIG9uZV9zaWRlZCwgdHdvX3NpZGVkKQoKdHNfcGxvdChtYSkKYGBgCgpBIHR3by1zaWRlZCBNQSBpcyBtb3JlIGFwcHJvcHJhdGUgdG8gYXBwbHkgYXMgYSBzbW9vdGhlciBvciBkYXRhIGZpbHRlciBtZXRob2QuIEEgb25lLXNpZGVkIE1BIG1ha2VzIHNlbnNlIHdoZW4geW91IG5lZWQgdG8gaGF2ZSB0aGUgbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zLgoKIyBUaGUgdGltZSBzZXJpZXMgY29tcG9uZW50cwoKUGF0dGVybnMgaW4gdGltZSBzZXJpZXMgYW5hbHlzaXMgY2FuIGJlIGNhdGVnb3JpemVkIGludG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgotICAgU3RydWN0dXJhbCBQYXR0ZXJuczogYWxzbyBrbm93biBhcyBzZXJpZXMgY29tcG9uZW50cy4gVGhlcmUgYXJlIHRocmVlIHR5cGVzIC0gdHJlbmQsIGN5Y2xlLCBhbmQgc2Vhc29uYWwuCgotICAgTm9uLXN0cnVjdHVyYWw6IGFsc28ga25vd24gYXMgdGhlIGlycmVndWxhciBjb21wb25lbnQgYW5kIHJlZmVycyB0byBhbnkgb3RoZXIgdHlwZXMgb2YgcGF0dGVybnMgaW4gdGhlIGRhdGEuCgpXZSBjYW4gdXNlIHRoZXNlIHR3byBncm91cHMgb2YgcGF0dGVybnMgdG8gZXhwcmVzcyB0aW1lIHNlcmllcyBkYXRhIHVzaW5nIHRoZSBmb2xsb3dpbmcgZXF1YXRpb24gd2hlbiB0aGUgc2VyaWVzIGhhcyBhbiBhZGRpdGl2ZSBzdHJ1Y3R1cmU6CgokJApZX3QgPSBUX3QgKyBTX3QgKyBDX3QgKyBJX3QKJCQKCkFuZCB3aGVuIHRoZSBzZXJpZXMgaGFzIGEgbXVsdGlwbGljYXRpdmUgc3RydWN0dXJlOgoKJCQKWV90ID0gVF90IFx0aW1lcyBTX3QgXHRpbWVzIENfdCBcdGltZXMgSV90CiQkCgojIyBUaGUgY3ljbGUgY29tcG9uZW50CgpgYGB7cn0KZGF0YSgiVVNVblJhdGUiKQoKdHNfaW5mbyhVU1VuUmF0ZSkKYGBgCgpXZSBkb24ndCBuZWVkIHRvIHBsb3QgdGhlIGVudGlyZSBzZXJpZXMsIHNvIHdlIHdpbGwgc3Vic2V0IGl0IHdpdGggYSBgd2luZG93YCBmdW5jdGlvbjoKCmBgYHtyfQp1bmVtcGxveW1lbnQgPC0gd2luZG93KFVTVW5SYXRlLCBzdGFydCA9IGMoMTk5MCwgMSkpCgp0c19wbG90KHVuZW1wbG95bWVudCkKYGBgCgojIyBUaGUgdHJlbmQgY29tcG9uZW50CgpBIHRyZW5kIGlzIGEgZ2VuZXJhbCBkaXJlY3Rpb24gaW4gYSBzZXJpZXMuCgpgYGB7cn0Kc2V0LnNlZWQoMTIzNCkKCnRzX25vbl90cmVuZCA8LSB0cyhydW5pZigyMDAsIDUsIDUuMiksCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAwMCwgMSksCiAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKYGBgCgojIyBUaGUgc2Vhc29uYWwgY29tcG9uZW50CgpBIHNlYXNvbmFsIHRyZW5kIGlzIG9uZSB0aGF0IGhhcyByZXBlYXRlZCB2YXJpYXRpb24gb3ZlciB0aW1lLgoKIyMgVGhlIHNlYXNvbmFsIGNvbXBvbmVudCB2ZXJzdXMgdGhlIGN5Y2xlIGNvbXBvbmVudAoKYGBge3J9CnVzZ2FzIDwtIGFzLnh0cyhVU2dhcykKZ2dwbG90KGRhdGEgPSB1c2dhcywgYWVzKHggPSB5ZWFyKGluZGV4KHVzZ2FzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1vbnRoKGluZGV4KHVzZ2FzKSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAoMSAvIGRhdGEpKSkgKwogIGdlb21fdGlsZSgpCmBgYAoKVGhlIHBsb3QgYWJvdmUgc2hvd3MgYSBzZWFzb25hbCBjeWNsZS4KCmBgYHtyfQp1c19lbXBfcnQgPC0gYXMueHRzKFVTVW5SYXRlKQoKZ2dwbG90KGRhdGEgPSB1c19lbXBfcnQsIGFlcyh4ID0geWVhcihpbmRleCh1c19lbXBfcnQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1vbnRoKGluZGV4KHVzX2VtcF9ydCksIGxhYmVsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IDEgLyBkYXRhKSkgKwogIGdlb21fdGlsZSgpCmBgYAoKVGhpcyBwbG90IHNob3dzIGN5Y2xlcy4KCiMjIFdoaXRlIG5vaXNlCgpBIHdoaXRlIG5vaXNlIHBhdHRlcm4gaXMgYSBsYWNrIG9mIGEgcGF0dGVybi4gVGhlcmUgYXJlIHNvbWUgbWV0aG9kcyB0byB0ZXN0IGlmIGEgc2VyaWVzIGlzIHdoaXRlIG5vaXNlLgoKLSAgIHBsb3QgaXQgb3V0IGFuIGV5ZWJhbGwKCi0gICBNZWFzdXJlIHRoZSBjb3JyZWxhdGlvbiB3aXRoIHRoZSBhdXRvY29ycmVsYXRpb24gZnVuY3Rpb24KCi0gICB0aGUgTGp1bmctQm94IHRlc3R6OyB0aGUgbnVsbCBoeXBvdGhlc2lzIGFzc3VtZXMgdGhhdCB0aGUgbGFncyBhcmUgbm90IGNvcnJlbGF0ZWQuCgojIyBUaGUgaXJyZWd1bGFyIGNvbXBvbmVudAoKVGhpcyBpcyB0aGUgcmVtYWluZGVyIGJldHdlZW4gdGhlIHNlcmllcyBhbmQgc3RydWN0dXJhbCBjb21wb25lbnRzLgoKIyBUaGUgYWRkaXRpdmUgdmVyc3VzIHRoZSBtdWx0aXBsaWNhdGl2ZSBtb2RlbAoKV2UgY2xhc3NpZnkgYSBzZXJpZXMgYXMgYWRkaXRpdmUgd2hlbmV2ZXIgdGhlcmUgaXMgZ3Jvd3RoIGluIHRoZSB0cmVuZCwgb3IgaWYgdGhlIGFtcGxpdHVkZSBvZiB0aGUgc2Vhc29uYWwgY29tcG9uZW50IHJlbWFpbnMgdGhlIHNhbWUgb3ZlciB0aW1lLgoKV2UgY2xhc3NpZnkgYSBzZXJpZXMgYXMgbXVsdGlwbGljYXRpdmUgd2hlbmV2ZXIgdGhlIGdyb3d0aCBvZiB0aGUgdHJlbmQgb3IgdGhlIG1hZ25pdHVkZSBvZiB0aGUgc2Vhc29uYWwgY29tcG9uZW50IGluY3JlYXNlcyBvciBkZWNyZWFzZXMgYnkgc29tZSBtdWx0aXBsaWNpdHkgZnJvbSBwZXJpb2QgdG8gcGVyaW9kIG92ZXIgdGltZS4KCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiBhbiBhZGRpdGl2ZSBzZXJpZXM6CgpgYGB7cn0KdHNfcGxvdChVU2dhcykKYGBgCgpIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBtdWx0aXBsaWNhdGl2ZSBzZXJpZXM6CgpgYGB7cn0KZGF0YSgiQWlyUGFzc2VuZ2VycyIpCgp0c19wbG90KEFpclBhc3NlbmdlcnMpCmBgYAoKIyMgSGFuZGxpbmcgbXVsdGlwbGljYXRpdmUgc2VyaWVzCgpNb3N0IGZvcmVjYXN0aW5nIG1vZGVscyBhc3N1bWUgdGhhdCB0aGUgdmFyaWF0aW9uIG9mIHRoZSBpbnB1dCBzZXJpZXMgcmVtYWlucyBjb25zdGFudCBvdmVyIHRpbWUuIFRoaXMgdXN1YWxseSBob2xkcyBmb3IgYSBzZXJpZXMgd2l0aCBhbiBhZGRpdGl2ZSBzdHJ1Y3R1cmUsIGJ1dCBmYWlscyB3aXRoIGEgbXVsdGlwbGljYXRpdmUgc3RydWN0dXJlLiBUaGUgY29tbW9uIHNvbHV0aW9uIGlzIHRvIGFwcGx5IGEgZGF0YSB0cmFuc2Zvcm1hdGlvbjoKCi0gICBsb2cgdHJhbnNmb3JtYXRpb246IGFwcGx5IHRoZSAkbG9nJCB0byBib3RoIHNpZGVzIG9mIHRoZSBzZXJpZXMgZXF1YXRpb24KCi0gICBib3gtY294IHRyYW5zZm9ybWF0aW9uOiBhcHBseWluZyBwb3dlciBvbiB0aGUgaW5wdXQgc2VyaWVzIHdpdGggdGhlIGJveC1jb3ggZm9ybXVsYQoKYGBge3J9CmxpYnJhcnkoZm9yZWNhc3QpCgphaXJfcGFzc2VuZ2VyX2xhbWJkYSA8LSBCb3hDb3gubGFtYmRhKEFpclBhc3NlbmdlcnMpCmFpcl9wYXNzZW5nZXJfbGFtYmRhCmBgYAoKV2UgY2FuIHVzZSB0aGUgY29lZmZpY2llbnQgdG8gdHJhbnNmb3JtIHRoZSBpbnB1dCBzZXJpZXMgd2l0aCB0aGUgYEJveENveGAgdHJhbnNmb3JtYXRpb24gYW5kIHBsb3QgaXQ6CgpgYGB7cn0KYWlyX3Bhc3Nlbmdlcl90cmFucyA8LSBCb3hDb3goQWlyUGFzc2VuZ2VycywgbGFtYmRhID0gYWlyX3Bhc3Nlbmdlcl9sYW1iZGEpCgp0c19wbG90KGFpcl9wYXNzZW5nZXJfdHJhbnMpCmBgYAoKIyBUaGUgZGVjb21wb3NpdGlvbiBvZiB0aW1lIHNlcmllcwoKT25jZSB0aGUgZGF0YSBoYXMgYmVlbiBjbGVhbmVkIGFuZCByZWZvcm1hdHRlZCwgd2UgbmVlZCB0byBpZGVudGlmeSB0aGUgc3RydWN0dXJlIG9mIHRoZSBzZXJpZXMgY29tcG9uZW50cy4gVGhlIGRlY29tcG9zaXRpb24gb2YgYSBzZXJpZXMgaXMgYSBnZW5lcmljIG5hbWUgZm9yIHRoZSBwcm9jZXNzIG9mIHNlcGFyYXRpbmcgYSBzZXJpZXMgaW50byBpdHMgY29tcG9uZW50cy4KCiMjIENsYXNzaWNhbCBzZWFzb25hbCBkZWNvbXBvc2l0aW9uCgpUaGlzIGlzIGEgdGhyZWUgc3RlcCBwcm9jZXNzOgoKMS4gIHRyZW5kIGVzdGltYXRpb246IHVzZXMgdGhlIE1BIGZ1bmN0aW9uIHRvIHJlbW92ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50IGZyb20gdGhlIHNlcmllcy4gVEhlIG9yZGVyIG9mIHRoZSBNQSBmdW5jdGlvbiBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBmcmVxdWVuY3kgb2YgdGhlIHNlcmllcy4KMi4gIFNlYXNvbmFsIGNvbXBvbmVudCBlc3RpbWF0aW9uOiBUd28gc3RlcCBwcm9jZXNzIHRoYXQgc3RhcnRzIHdpdGggZGV0cmVuZGluZyB0aGUgc2VyaWVzIGJ5IHN1YnRyYWN0aW5nIHRoZSB0cmVuZCBlc3RpbWF0aW9uIGZyb20gdGhlIHByZXZpb3VzIHN0ZXAuIEFmdGVyIHRoZSBzZXJpZXMgaXMgZGV0cmVuZGVkLCB0aGUgbmV4dCBzdGVwIGlzIHRvIGVzdGltYXRlIHRoZSBzZWFzb25hbCBjb21wb25lbnQgZm9yIGVhY2ggZnJlcXVlbmN5IHVuaXQuIFRoaXMgaXMgZG9uZSBieSBncm91cGluZyB0aGUgb2JzZXJ2YXRpb25zIGJ5IHRoZWlyIGZyZXF1ZW5jeSB1bml0IGFuZCB0aGVuIGF2ZXJhZ2luZyBlYWNoIGdyb3VwLgozLiAgSXJyZWd1bGFyIGNvbXBvbmVudCBlc3RpbWF0aW9uOiBzdWJ0cmFjdGluZyB0aGUgZXN0aW1hdGlvbiBvZiB0aGUgdHJlbmQgYW5kIHNlYXNvbmFsIGNvbXBvbmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgc2VyaWVzLgoKV2UgY2FuIGRvIGFsbCBvZiB0aGlzIHdpdGggdGhlIGBkZWNvbXBvc2UoKWAgZnVuY3Rpb246CgpgYGB7cn0KdXN2X2RlY29tcG9zZWQgPC0gZGVjb21wb3NlKFVTVlNhbGVzKQoKc3RyKHVzdl9kZWNvbXBvc2VkKQpgYGAKCi0gICBgeGAgaXMgdGhlIG9yaWdpbmFsIHNlcmllcwoKLSAgIGBzZWFzb25hbGAgaXMgdGhlIGVzdGltYXRlIG9mIHRoZSBzZWFzb25hbCB0cmVuZAoKLSAgIGB0cmVuZGAgaXMgdGhlIGVzdGltYXRlIG9mIHRoZSBzZXJpZXMgdHJlbmQKCi0gICBgcmFuZG9tYCBpcyB0aGUgaXJyZWd1bGFyIGNvbXBvbmVudAoKLSAgIGBmaWd1cmVgIGVzdGltYXRlZCBzZWFzb25hbCBmaWd1cmUgb25seQoKLSAgIGB0eXBlYCB0aGUgdHlwZSBvZiBkZWNvbXBvc2l0aW9uLCBlaXRoZXIgYWRkaXRpdmUgb3IgbXVsdGlwbGljYXRpdmUKCmBgYHtyfQpwbG90KHVzdl9kZWNvbXBvc2VkKQpgYGAKCkFuZCB3aXRoIGEgbXVsdGlwbGljYXRpdmUgbW9kZWw6CgpgYGB7cn0KYWlyX2RlY29tcG9zZWQgPC0gZGVjb21wb3NlKEFpclBhc3NlbmdlcnMsIHR5cGUgPSAibXVsdGlwbGljYXRpdmUiKQoKcGxvdChhaXJfZGVjb21wb3NlZCkKYGBgCgpPbmUgbGltaXRhdGlvbiBvZiB0aGUgY2xhc3NpY2FsIGRlY29tcG9zaXRpb24gbWV0aG9kIGlzIHRoYXQgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCB1c2VzIHRoZSBhcml0aG1ldGljIGF2ZXJhZ2UuIFRoaXMgbWVhbnMgdGhhdCB0aGVyZSBpcyBhIHNpbmdsZSBzZWFzb25hbCBjb21wb25lbnQgZXN0aW1hdGlvbiBmb3IgZWFjaCBjeWNsZSB1bml0LiBUaGlzIGlzIGZpbmUgd2l0aCBhZGRpdGl2ZSBtb2RlbHMsIGJ1dCBjYW4gYmUgcHJvYmxlbWF0aWMgd2l0aCBtdWx0aXBsaWNhdGl2ZSBtb2RlbHMgc2luY2UgdGhlIHNlYXNvbmFsIGFzcGVjdCBjaGFuZ2VzIG92ZXIgdGltZS4KCiMgU2Vhc29uYWwgQWRqdXN0bWVudAoKU2Vhc29uYWwgYWRqdXN0bWVudCBpcyB0aGUgcHJvY2VzcyBvZiByZW1vdmluZyB0aGUgc2Vhc29uYWwgZmx1Y3R1YXRpb24gZnJvbSBhIHNlcmllcy4gVGhlIHRyYW5zZm9ybWF0aW9uIHByb2Nlc3Mgb2YgdGhlIHNlYXNvbmFsIGFkanVzdG1lbnQgbWV0aG9kIGlzIHN0cmFpZ2h0Zm9yd2FyZDoKCjEuICBFc3RpbWF0ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50IHVzaW5nIGEgZGVjb21wb3NpdGlvbiBwcm9jZXNzCjIuICBSZW1vdmUgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCBmcm9tIHRoZSBzZXJpZXMsIHdoaWNoIGxlYXZlcyB0aGUgc2VyaWVzIHdpdGggb25seSB0aGUgdHJlbmQgYW5kIHRoZSBpcnJlZ3VsYXIgY29tcG9uZW50CjMuICBPcHRpb25hbGwsIHlvdSBjYW4gYXBwbHkgYSBzbW9vdGhpbmcgZnVuY3Rpb24gdG8gcmVtb3ZlIG5vaXNlIGFuZCBvdXRsaWVycwo=